import React, { useRef } from 'react'
import { XYCoord } from 'dnd-core'
import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd'

export interface CardProps {
    id: any;
    index: number;
    move?: (dragIndex: number, hoverIndex: number) => void;
    end: (id: string, dragIndex: number) => void;
}

interface DragItem {
    index: number;
    id: string;
    type: string;
}
const ItemTypes = {
  CARD: 'card'
}

const Card: React.FC<CardProps> = ({ id, end, move, children, index }) => {
  const ref = useRef<HTMLDivElement>(null)
  const [, drop] = useDrop({
    accept: ItemTypes.CARD,
    hover (item: DragItem, monitor: DropTargetMonitor) {
      if (!ref.current) {
        return
      }
      const dragIndex = item.index
      const hoverIndex = index

      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return
      }

      // Determine rectangle on screen
      const hoverBoundingRect = ref.current!.getBoundingClientRect()

      // Get vertical middle
      const hoverMiddleY =
                (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2

      // Determine mouse position
      const clientOffset = monitor.getClientOffset()

      // Get pixels to the top
      const hoverClientY =
                (clientOffset as XYCoord).y - hoverBoundingRect.top

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%

      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return
      }

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return
      }
      // Time to actually perform the action

      if (move) {
        move(dragIndex, hoverIndex)
      }

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      // eslint-disable-next-line no-param-reassign
      item.index = hoverIndex
    }
  })

  const [{ isDragging }, drag] = useDrag({
    item: { type: ItemTypes.CARD, id, index },
    collect: (monitor: any) => ({
      isDragging: monitor.isDragging()
    }),
    end: (item?: { id: string; index: number }) => {
      if (!item) {
        return
      }
      end(item.id, item.index)
    }
  })

  const opacity = isDragging ? 0.4 : 1
  drag(drop(ref))
  return (
        <div ref={ref} style={{ opacity }}>
            {children}
        </div>
  )
}

export default Card
